package io.github.codelifeleno.jdbrelease.util;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.resource.FileResource;
import cn.hutool.core.io.resource.Resource;
import cn.hutool.core.io.resource.ResourceUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.core.util.URLUtil;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.*;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.List;
import java.util.function.Consumer;
import java.util.jar.JarEntry;
import java.util.jar.JarFile;
import java.util.regex.Pattern;
import java.util.stream.Stream;

/**
 * JAR 资源操作工具类
 * 功能：
 * 1. 通过正则表达式匹配 JAR 包内的资源路径
 * 2. 读取匹配到的资源内容
 * 3. 提取资源到临时目录
 * 4 5 6 获取资源目录中满足正则表达式的文件Resource对象
 */
public class JDBResourceUtils {

    private static final Logger log = LoggerFactory.getLogger(JDBResourceUtils.class);

    /**
     * 根据正则表达式查找 JAR 包内匹配的资源路径
     *
     * @param regex 正则表达式（路径需使用 `/` 分隔符，例如 "^config/.*\\.properties$"）
     * @return 匹配的资源路径列表（使用 `/` 分隔符的相对路径）
     */
    public static List<String> findMatchingResources(Class clazz, String regex) throws IOException, URISyntaxException {
        List<String> matchedPaths = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);

        // 获取当前类所在的 JAR 文件路径（仅在打包后生效）
        URL jarUrl = clazz.getProtectionDomain().getCodeSource().getLocation();
        String jarPath = Paths.get(jarUrl.toURI()).toString();

        if (jarPath.endsWith(".jar")) {
            // 从 JAR 包中遍历条目
            try (JarFile jar = new JarFile(jarPath)) {
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String entryName = entry.getName();
                    if (pattern.matcher(entryName).matches() && !entry.isDirectory()) {
                        matchedPaths.add(entryName);
                    }
                }
            }
        } else {
            // 在 IDE 中运行时，从类路径目录遍历文件
            URL resourcesDir = clazz.getClassLoader().getResource("");
            if (resourcesDir != null) {
                Path rootPath = Paths.get(jarPath);
                try (Stream<Path> stream = Files.walk(rootPath)) {
                    stream.filter(Files::isRegularFile)
                            .forEach(path -> {
                                // 转换为类路径格式（使用 / 分隔符）
                                String relativePath = rootPath.relativize(path).toString()
                                        .replace(File.separatorChar, '/');
                                if (pattern.matcher(relativePath).matches()) {
                                    matchedPaths.add(relativePath);
                                }
                            });
                }
            }
        }
        return matchedPaths;
    }


    public static void handlerResource(String resourcePath, Consumer<InputStream> inputStreamConsumer) throws IOException {
        try (InputStream is = inputStreamConsumer.getClass().getClassLoader().getResourceAsStream(resourcePath)) {
            if (is == null) throw new FileNotFoundException("资源不存在: " + resourcePath);
            inputStreamConsumer.accept(is);
        }
    }


    /**
     * 将 JAR 包内的资源提取到临时目录
     *
     * @param resourcePath 资源路径（使用 `/` 分隔符）
     * @param targetDir    目标目录（如果为 null 则使用系统临时目录）
     * @return 提取后的文件完整路径
     */
    public static String extractResourceToTemp(Class clazz, String resourcePath, Path targetDir)
            throws IOException {
        // 设置目标目录
        Path outputDir = (targetDir != null) ? targetDir : Paths.get(System.getProperty("java.io.tmpdir"));
        Path outputPath = outputDir.resolve(resourcePath);

        // 确保父目录存在
        Files.createDirectories(outputPath.getParent());

        // 从 JAR 或类路径读取资源
        try (InputStream is = clazz.getClassLoader()
                .getResourceAsStream(resourcePath)) {
            if (is == null) throw new FileNotFoundException("资源不存在: " + resourcePath);
            Files.copy(is, outputPath, StandardCopyOption.REPLACE_EXISTING);
        }
        return outputPath.toString();
    }

    /**
     * 获取资源目录中所有配置文件以及路径下的配置文件
     * @return 所有资源文件的集合
     * @throws URISyntaxException uri 转化异常
     * @throws IOException 文件不可读取的异常
     */
    public static List<Resource> getResources() throws URISyntaxException, IOException {
        return getResources(StrUtil.EMPTY);
    }

    /**
     * 根据指定目录获取目标目录中所有配置文件以及路径下的配置文件
     * @param resourceDirectory 目标资源目录
     * @return 所有资源文件的集合
     * @throws URISyntaxException uri 转化异常
     * @throws IOException 文件不可读取的异常
     */
    public static List<Resource> getResources(String resourceDirectory) throws URISyntaxException, IOException {
        return getResources(resourceDirectory, StrUtil.EMPTY);
    }

    /**
     * 根据指定目录获取目标目录中满足正则表达式的配置文件
     * @param resourceDirectory 目标资源目录
     * @param regex 正则表达式
     * @return 所有资源文件的集合
     * @throws URISyntaxException uri 转化异常
     * @throws IOException 文件不可读取的异常
     */
    public static List<Resource> getResources(String resourceDirectory, String regex) throws URISyntaxException, IOException {
        if (StrUtil.isBlank(resourceDirectory)) {
            resourceDirectory = StrUtil.EMPTY;
        }
        if (StrUtil.isBlank(regex)) {
            regex = ".*";
        }
        ArrayList<Resource> resources = new ArrayList<>();
        Pattern pattern = Pattern.compile(regex);
        Resource resource = ResourceUtil.getResourceObj(resourceDirectory);
        if (URLUtil.isFileURL(resource.getUrl())) {
            Path path = Paths.get(resource.getUrl().toURI());
            boolean isDir = Files.isDirectory(path);
            if (isDir){
                List<File> files = FileUtil.loopFiles(path, pathname -> pattern.matcher(pathname.getAbsolutePath()).matches());
                for (File file : files) {
                    resources.add(new FileResource(file));
                }
            }else{
                if (pattern.matcher(resource.getUrl().toString()).matches()) {
                    resources.add(resource);
                }
            }
        }else if (URLUtil.isJarURL(resource.getUrl())) {
            try (JarFile jar = URLUtil.getJarFile(resource.getUrl())) {
                Enumeration<JarEntry> entries = jar.entries();
                while (entries.hasMoreElements()) {
                    JarEntry entry = entries.nextElement();
                    String entryName = entry.getName();
                    if (pattern.matcher(entryName).matches()) {
                        resources.add(ResourceUtil.getResourceObj(entry.getName()));
                    }
                }
            }
        }
        return resources;
    }


    /**
     * 示例用法
     */
    public static void main(String[] args) throws URISyntaxException, IOException {
        try {
            // 1. 查找所有配置文件
            String regex = ".*/.sql"; // 匹配 config 目录下的 .properties 文件
            List<String> files = findMatchingResources(JDBResourceUtils.class, regex);
            System.out.println("匹配到的文件: " + files);

//            // 2. 读取第一个文件内容
//            if (!files.isEmpty()) {
//                String content = readResourceContent(JDBResourceUtils.class, files.get(0));
//                System.out.println("\n文件内容示例:\n" + content.substring(0, 100) + "...");
//            }
            files.forEach(e -> {
                try {
                    handlerResource(e, a -> {
                        BufferedReader br = new BufferedReader(new InputStreamReader(a, Charset.defaultCharset()));
                        br.lines().forEach(System.out::println);
                    });
                } catch (IOException ex) {
                    log.error(ex.getMessage(), e);
                }
            });

            // 3. 提取文件到临时目录
            if (!files.isEmpty()) {
                String extractedPath = extractResourceToTemp(JDBResourceUtils.class, files.get(0), null);
                System.out.println("\n文件已提取到: " + extractedPath);
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
        List<Resource> resources = getResources("", ".*sql$");
        for (Resource resource : resources) {
            System.out.println(resource.getUrl());
        }
    }
}
